import _axios from 'axios'
import ElementUI from 'element-ui'
import JSONBig from 'json-bigint'
import auth from './auth'
import { $lc } from './i18n/index'
const _Loading = ElementUI.Loading
const _Message = ElementUI.Message

const fileMap = {
  pdf: 'application/pdf',
  jpeg: 'image/jpeg',
  jpg: 'image/jpeg',
  bmp: 'image/x-ms-bmp',
  png: 'image/png',
  gif: 'image/gif',
  svg: 'image/svg+xml',
  svgz: 'image/svg+xml',
  ico: 'image/x-icon',
  json: 'application/json',
  doc: 'application/msword',
  docx: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
  xls: 'application/vnd.ms-excel',
  xlsx: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
  ppt: 'application/vnd.ms-powerpoint',
  pptx: 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
  csv: 'text/plain',
  zip: 'application/zip',
  '7z': 'application/x-7z-compressed',
  rar: 'application/x-rar-compressed',
  mp3: 'audio/mpeg',
  mp4: 'video/mp4',
  avi: 'video/x-msvideo',
  wmv: 'video/x-ms-wmv',
  flv: 'video/x-flv',
  swf: 'application/x-shockwave-flash'
}

/* 添加msg */
function showMsg(msg, single = true) {
  if (!single || !document.querySelector('.xhr-msg-top')) {
    _Message({
      showClose: true,
      message: msg,
      type: 'error',
      customClass: 'xhr-msg-top'
    })
  }
}
/* 添加loading */
let loadingBox
let loadingCount = 0
function showLoading(opt) {
  let loading = opt.loading
  if (loading === true) {
    if (loadingCount === 0 && !document.querySelector('.xhr-loading-top:not(.el-loading-fade-leave-active)')) {
      loadingBox = _Loading.service({
        lock: true,
        text: $lc('加载中'),
        background: 'rgba(0, 0, 0, 0.1)',
        customClass: 'xhr-loading-top'
      })
    }
    loadingCount++
  }
}
function closeLoading(opt) {
  let loading = opt.loading
  if (loading === true) {
    setTimeout(() => {
      loadingCount--
      loadingCount === 0 && loadingBox && loadingBox.close()
    }, 16)
  } else if (typeof loading === 'function') {
    loading()
  }
}
/* 请求防抖 */
let debounceObj = {}

const config = {
  baseURL: process.env.VUE_APP_BASE_API || '',
  crossDomain: true, // 允许跨域
  // withCredentials: true, // 跨域携带cookie
  timeout: 120000,
  validateStatus(status) {
    return status === 200
  },
  // 处理big数据
  transformResponse: [
    function (data) {
      if (data instanceof Blob) {
        return data
      } else {
        const json = JSONBig({ storeAsString: true })
        const res = json.parse(data)
        return res
      }
    }
  ]
}
const axios = _axios.create(config)

axios.interceptors.request.use((opt) => {
  opt.headers = auth.setHeaders(opt.headers, opt.OperationDesc)
  return opt
})

function errorFn(status, msg, noMsg, isErr, res) {
  if (status === 401 || msg === 'Request failed with status code 401') {
    noMsg || showMsg($lc('超时未操作，请重新登录！'))
    setTimeout(() => {
      if (navigator.userAgent.includes('NSTC-WebEntry')) {
        localStorage.clear()
        sessionStorage.clear()
      } else {
        auth.removeToken()
      }
    }, 1000)
  } else if (status === 400) {
    noMsg || showMsg($lc('400，参数错误！'))
  } else if (status === 404) {
    noMsg || showMsg($lc('404，网络连接失败！'))
  } else if (status === 500) {
    noMsg || showMsg($lc('500，服务器链接失败！'))
  } else if (status === 'ECONNABORTED' && msg.includes('timeout')) {
    noMsg || showMsg($lc('请求超时'))
  } else if (msg === 'Network Error') {
    noMsg || showMsg($lc('请求错误'))
  } else if (status >= 900 || status === -1) {
    noMsg || showMsg(msg)
  } else {
    // noMsg || showMsg(msg)
  }
  throw { code: status, msg: msg, response: res }
}

axios.interceptors.response.use(
  (res) => {
    let status = (res.data && res.data.code) || res.status
    if (Number(status) === 200) {
      return res
    } else {
      let msg = (res.data && (res.data.msg || res.data.message)) || ''
      let noMsg = res.config && res.config.noMsg

      return errorFn(status, msg, noMsg, false, res)
    }
  },
  (err) => {
    let status = err.status
    let msg = err.message || ''
    let noMsg = err.config && err.config.noMsg

    return errorFn(status, msg, noMsg, true)
  }
)

function request(opt) {
  let loading = opt.loading === undefined ? true : opt.loading
  showLoading({ loading })

  if (debounceObj[opt.method + opt.url]) {
    debounceObj[opt.method + opt.url].finally(() => {
      closeLoading({ loading })
    })

    // 短时间多次请求,均返回第一次请求结果
    return debounceObj[opt.method + opt.url]
  }

  let resPro = new Promise((resolve, reject) => {
    axios
      .request(opt)
      .then((res) => {
        if (opt.responseType === 'blob') {
          let filename = getFilename(res.headers['content-disposition'])
          if (filename && res.data) {
            filename = filename.replace(/"/g, '')
            // 调整blob类型
            let I = filename.lastIndexOf('.')
            if (I !== -1) {
              let type = undefined
              let suffix = filename.slice(I + 1)
              type = fileMap[suffix]
              if (type && res.data instanceof Blob && res.data.type !== type) {
                res.data = new Blob([res.data], { type: type })
              }
            }
            res.data.name = filename
          }
          if (res.data.size === 0) {
            reject({ code: 404, msg: opt.url + $lc('请求返回文件大小0KB') })
          } else {
            resolve(res.data)
          }
        } else {
          if (typeof res.data === 'object' && res.data.data === undefined) {
            res.data.data = {}
          }
          resolve(res.data)
        }
      })
      .catch((error) => {
        reject(error)
      })
  })

  resPro.finally(() => {
    delete debounceObj[opt.method + opt.url]

    closeLoading({ loading })
  })
  debounceObj[opt.method + opt.url] = resPro
  return resPro
}

function getFilename(cd = '') {
  let cdArr = cd.split(';')
  let filename = cdArr.find((d) => /filename/i.test(d))
  if (filename) {
    filename = filename.split('=')
    if (filename[1]) {
      return decodeURI(filename[1].trim())
    }
  }
  return ''
}

// 自定义axios
function customAxios(opt) {
  return request(opt)
}
customAxios.defaults = axios.defaults
/** @returns {Promise} */
customAxios.request = request
/** @returns {Promise} */
customAxios.get = function (url, params = {}, opt = {}) {
  return request(Object.assign({ method: 'get', url, params }, opt))
}
/** @returns {Promise} */
customAxios.post = function (url, data = {}, opt = {}) {
  return request(Object.assign({ method: 'post', url, data }, opt))
}
/** @returns {Promise} */
customAxios.put = function (url, data = {}, opt = {}) {
  return this.request(Object.assign({ method: 'put', url, data }, opt))
}
/** @returns {Promise} */
customAxios.delete = function (url, data = {}, opt = {}) {
  return this.request(Object.assign({ method: 'delete', url, data }, opt))
}

export default customAxios
